package Worker;
import Commons.Address;
import Commons.Indirizzi;
import Commons.ServerTrasferimentoFileUDP;
import Commons.TaskDescriptor;
import Commons.WorkerDescriptor;
import Discovery.DiscoveryProxyFactory;
import Discovery.WorkerDiscoveryProxy;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.UnknownHostException;
import Commons.Logging.Log;
import Commons.Logging.Logger;
import javax.xml.stream.XMLStreamException;


/**Questa classe descrive il Worker.
 *
 * @author Team5
 */
public class Worker implements AbstractWorker,Runnable{
    /**
     * 
     */
   
    private String id;
    private TQueueManager tqmanager;
    private Logger l;


    public Worker() throws UnknownHostException, XMLStreamException, InterruptedException, IOException{

            
             id=this.getClass().getSimpleName()+this.hashCode();
             l=new Logger("log"+this.id+".xml",this.getClass().getSimpleName());
             l.logging(new Log(this.getClass().getSimpleName(),id, "StartWorker",String.valueOf(System.currentTimeMillis()) ));
             System.out.println("Worker(): creo un istanza del TQueueManager");
             l.logging(new Log(this.getClass().getSimpleName(),id, "Creazione di un istanza del TQueueManager",String.valueOf(System.currentTimeMillis()) ));
            
             tqmanager= new TQueueManager();
             
             Thread t1=new Thread(tqmanager);
             
             t1.start();

             System.out.println("Worker(): creo un istanza del ServerTrasferimentoFileUDP");
             l.logging(new Log(this.getClass().getSimpleName(),id, "Creazione di un istanza del ServerTrasferimentoFileUDP",String.valueOf(System.currentTimeMillis()) ));
             ServerTrasferimentoFileUDP stfu= new ServerTrasferimentoFileUDP("pippo",Indirizzi.portaRicezioneFileWorker);//19000
             Thread t3=new Thread(stfu);
             
             //start server gestore trasferimento file
             t3.start();
             
             Thread t2=new Thread(this);
             t2.start();
             




       

    }
    /**
     *
     * @param ts
     * @return
     */
    public int exec(TaskDescriptor ts) {
      try
      {
         System.out.println("WORKER: exec(). Output del TaskDescriptor Esecuzione ##########");
         l.logging(new Log(this.getClass().getSimpleName(),id, "exec(),Output sul Td "+ts.toString(),String.valueOf(System.currentTimeMillis()) ));
         String commandArray = ts.getCommand();
         Runtime runtime = Runtime.getRuntime();
         Process process = runtime.exec(commandArray);
         InputStreamReader tempReader = new InputStreamReader( new BufferedInputStream(process.getInputStream()));
         BufferedReader reader = new BufferedReader(tempReader);
         while (true){
                String line = reader.readLine();
                if (line == null)
                        break;
                System.out.println(line);
                }
         System.out.println("WORKER: exec(). Output del TaskDescriptor Fine ##########");
          l.logging(new Log(this.getClass().getSimpleName(),id, "exec(),End Output sul Td "+ts.toString(),String.valueOf(System.currentTimeMillis()) ));
        }

        catch(Exception e)
        {
        }
       return 1;

    }
    public String getID(){
        return this.id;
    }
    public void run() {
       try
       {
             
             System.out.println("WORKER: creo il WorkerDiscoveryProxy");
             l.logging(new Log(this.getClass().getSimpleName(),id, "Creazione del Worker Discovery Proxy",String.valueOf(System.currentTimeMillis()) ));
             DiscoveryProxyFactory proxyFactory = new DiscoveryProxyFactory();
             WorkerDiscoveryProxy workerProxyDiscovery = proxyFactory.getProxy();
             WorkerDescriptor wd = new WorkerDescriptor();

             Address mioAddress = new Address();
             mioAddress.setPort(Indirizzi.portaRicezioneTDWorker); //La porta del servizio. Della coda.(Immaginiamo)
             mioAddress.setIP(Indirizzi.indirizzoWorker);

             wd.setAddr(mioAddress);
             wd.setStatus(WorkerDescriptor.WorkerStatus.Free);

             //Il Worker esegue la registrazione al Discovery
             //Implementare la comunicazione
              wd.setVectorClock(l.getVectorClock());
              int posizioneNellaListaDelDiscovery = workerProxyDiscovery.addworker(wd);

              System.out.println("WORKER: Il discovery mi ha aggiunto. INDEX: "+posizioneNellaListaDelDiscovery);
              l.logging(new Log(this.getClass().getSimpleName(),id, "Inserimento nella lista del Discovery avvenuto",String.valueOf(System.currentTimeMillis()) ));
              while(true)
             {
                  
                          System.out.println("WORKER: mi metto in wait in attesa di un Notify()");
                          synchronized(tqmanager.getTQueue()){
                          while(tqmanager.getTQueue().isEmpty())
                              tqmanager.getTQueue().wait();
                          System.out.println("WORKER: sono stato svegliato-> la coda non è vuota, mi accingo a consumare");
                          TaskDescriptor td = tqmanager.dequeue();
                          l.merge(td.getVectorClock());

                          Thread.sleep((long) (2500));
                          System.out.println("MANAGER: ho estratto il TD "+td.getID());
                          l.logging(new Log(this.getClass().getSimpleName(),id, "Estrazione del td "+td.toString(),String.valueOf(System.currentTimeMillis()) ));
                          wd.setStatus(WorkerDescriptor.WorkerStatus.Working);

                          wd.setVectorClock(l.getVectorClock());
                          workerProxyDiscovery.updateWorker(posizioneNellaListaDelDiscovery, wd);
                          this.exec(td);
                          wd.setStatus(WorkerDescriptor.WorkerStatus.Free);
                          wd.setVectorClock(l.getVectorClock());

                          workerProxyDiscovery.updateWorker(posizioneNellaListaDelDiscovery, wd);
              }




    }



       }
        catch(Exception ee)
                       {
                         ee.printStackTrace();
                       }



    }
}


   

   


